package fi.solita.dojo.mazeserver.game

import swing._

import scala.actors._
import scala.actors.Actor._
import fi.solita.dojo.mazeserver._
import fi.solita.dojo.mazeserver.client._
import fi.solita.dojo.mazeserver.map._
import fi.solita.dojo.mazeserver.game.internal._

abstract sealed class ClientMessage()
case class Initialize() extends ClientMessage
case class NewPlayer(player: String) extends ClientMessage
case class ClientCommand(player: String, message: String) extends ClientMessage
case class Quit(player: String) extends ClientMessage
case class ForceAction() extends ClientMessage
case class NewMap() extends ClientMessage
case class StartStop() extends ClientMessage

// All operations which change the game state must come through here

object GameActor extends Actor {
	import GameWorld._

	def act() {
		react {

		case StartStop() => {
			running = !running
			if (running) executeActions()
			publishUIEvents()		  
			act()
		}

		case NewMap() => {
			newMap()	
			publishUIEvents() 
			act()
		}

		case ForceAction() => {
			executeActions()
			publishUIEvents()
			act()
		}

		case ClientCommand(playerName:  String, commandString:  String) => {
			val player = getPlayer(playerName)
			setAction(player, Some(parse(commandString)))
			if (playerList.allPlayersHaveActions && running) executeActions()
			publishUIEvents   
			act()
		}

		case NewPlayer(playerName: String) => {
			if (!reservedName(playerName)) addPlayer(playerName)
			sendPlayerStatus(playerName)
			publishUIEvents
			act()
		}

		case Quit(playerName: String) => {
			ClientService ! Remove(playerName)
			//removePlayer(playerName)
			publishUIEvents
			act()
		}
		}
	}  

	private def getPlayer(playerName: String): Player = {
			val player = playerList.getPlayer(playerName)
			player match {
			case Some(p) => p
			case None => throw new IllegalStateException("Unknown player")
			}
	} 

	private def executeActions() {
		GameWorld.executeActions()

		sendAllPlayerStatus()

		publishUIEvents
	}

	private def sendAllPlayerStatus() = playerList.players foreach ((p: Player) => sendPlayerStatus(p.name))

	private def sendPlayerStatus(name: String) {
		ClientService ! Write(name, playerMessage(name))
	}

	private def parse(commandString: String): GameAction = {
			val actions = GameAction.allActions() filter (_.toString() == commandString)
			if (actions.size == 0) DoNothing() else actions.apply(0)
	}

	private def playerMessage(name: String): String = {
			val playerMsg = playerList.players.mkString("(", " ", ")")
			val gameStatus = "(" + GameWorld.map.toString + ")"
			"(" + gameStatus + " " + playerMsg + ")"
	}
}



